package org.lex.net.ftp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.Charset;

import org.lex.net.ftp.parser.FileListParser;


public class RFC959FTPClient extends RawFTPClient implements IRFC959FTPClient {
	public RFC959FTPClient() {
		super();
	}

	public void abort() throws IOException {
		this.issueCommandAndReadResponseAndCheckReplyCode("ABOR");
	}

	public OutputStream append(String file) throws IOException {
		Socket dc = openDataConnection("APPE " + file);
		return dc.getOutputStream();
	}

	public void ascii() throws IOException {
		issueCommandAndReadResponseAndCheckReplyCode("TYPE A");
		binaryMode = false;
	}

	public void binary() throws IOException {
		issueCommandAndReadResponseAndCheckReplyCode("TYPE I");
		binaryMode = true;
	}

	public void cwd(String path) throws IOException {
		this.maybePending();
		if (false == "".equals(path))
			issueCommandAndReadResponseAndCheckReplyCode("CWD", path);
	}

	public void cdUp() throws IOException {
		issueCommandAndReadResponseAndCheckReplyCode("CDUP");
	}

	public String feature() throws IOException {
		this.issueCommandAndReadResponseAndCheckReplyCode("FEAT");
		return this.getLastResponseString();
	}

	public InputStream get(String file) throws IOException {
		Socket dc = openDataConnection("RETR " + file);
		return dc.getInputStream();
	}

	public InputStream get(String file, long offset) throws IOException {
		this.restart(offset);
		return this.get(file);
	}

	public IFTPFile[] list() throws IOException {
		String pwd = this.pwd();
		Charset cs = this.getServerCharset();
		IFTPFile[] lists = FileListParser.parse(this.listStream(), pwd, cs).toArray(new IFTPFile[0]);
		this.maybePending();
		return lists;
	}

	public InputStream listStream() throws IOException {
		Socket socket = openDataConnection("LIST");
		return socket.getInputStream();
	}

	public InputStream nameListStream(String path) throws IOException {
		Socket dc;
		if (path != null)
			dc = openDataConnection("NLST " + path);
		else
			dc = openDataConnection("NLST");
		return dc.getInputStream();
	}

	public void noop() throws IOException {
		issueCommandAndReadResponseAndCheckReplyCode("NOOP");
	}

	public OutputStream put(String file) throws IOException {
		Socket dc = openDataConnection("STOR " + file);
		return dc.getOutputStream();
	}

	public String pwd() throws IOException {
		issueCommandAndReadResponseAndCheckReplyCode("PWD");
		String s = getLastResponseString();
		if (!s.startsWith("257"))
			throw new FTPCommandException("PWD failed. " + s);
		else
			return s.substring(5, s.lastIndexOf('"'));
	}

	public void quit() throws IOException {
		this.issueCommandAndReadResponse("QUIT");
	}

	public void reInit() throws IOException {
		issueCommandAndReadResponseAndCheckReplyCode("REIN");
		isLoggedIn = false;
	}

	public void rename(String from, String to) throws IOException {
		issueCommandAndReadResponseAndCheckReplyCode("RNFR", from);
		issueCommandAndReadResponseAndCheckReplyCode("RNTO", to);
	}

	public void restart(long pos) throws IOException {
		issueCommandAndReadResponseAndCheckReplyCode("REST", Long.toString(pos));
	}

	@Override
	public long size(String file) throws IOException {
		super.issueCommandAndReadResponseAndCheckReplyCode("SIZE", file);
		String len = super.getLastResponseString();
		// 2xx 12345
		return Long.parseLong(len.substring(4));
	}

	public String system() throws IOException {
		issueCommandAndReadResponseAndCheckReplyCode("SYST");
		String s = getLastResponseString();
		if (!s.startsWith("215"))
			throw new FTPCommandException("SYST failed." + s);
		else
			return s.substring(4);
	}

	private void maybePending() throws IOException {
		if (1 == (this.getLastReplyCode() / 100))
			this.readReplyCode();
	}
}
